package com.zk.config.web.controller;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.ZKUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.google.gson.Gson;
import com.zk.config.api.util.ComUtil;
import com.zk.config.api.util.ZkCom;
import com.zk.config.api.util.ZkOperate;
import com.zk.config.web.constants.Constants;
import com.zk.config.web.model.Response;
import com.zk.config.web.op.Zk;
import lombok.Setter;

@Controller
@RequestMapping("/op")
public class ZkOpController {
	private static final Logger logger = LoggerFactory.getLogger(ZkOpController.class);
	private static final String SEPARATOR = "/";
	private Gson gson = new Gson();
	@Setter
	@Value("${zookeeper.backup.directory}")
	private String backupDirPath;
	
	@RequestMapping("/create")
	public String create(Model model, String parent, String name, String data) {
		String cxnstr = getCxnstr();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		parent = StringUtils.isBlank(parent) ? SEPARATOR : StringUtils.trimToEmpty(parent);
		parent = StringUtils.endsWith(parent, SEPARATOR) ? parent : parent + SEPARATOR;
		name = StringUtils.startsWith(name, SEPARATOR) ? StringUtils.substring(name, 1) : name;
		Zk zk = new Zk(cxnstr);
		String path = parent + name;
		zk.create(path, data.getBytes(Charset.forName("UTF-8")));
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr+"&path=" + path;
	}
	
	@RequestMapping("/createNode")
	public void createNode(HttpServletResponse response, String parent, String name) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		parent = StringUtils.isBlank(parent) ? SEPARATOR : StringUtils.trimToEmpty(parent);
		parent = StringUtils.endsWith(parent, SEPARATOR) ? parent : parent + SEPARATOR;
		name = StringUtils.startsWith(name, SEPARATOR) ? StringUtils.substring(name, 1) : name;
		Zk zk = new Zk(cxnstr);
		String path = parent + name;
		zk.create(path, null);
		logger.info("createNode, cxnstr:{}, path:{}", cxnstr, path);
		writeResponse(response, res);
	}

	@RequestMapping("/edit")
	public String edit(Model model, String path, String data) {
		String cxnstr = getCxnstr();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		path = getPath(path);
		Zk zk = new Zk(cxnstr);
		zk.edit(path, data.getBytes(Charset.forName("UTF-8")));
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr+"&path=" + path;
	}

	@RequestMapping("/delete")
	public String delete(Model model, String path, String data) {
		String cxnstr = getCxnstr();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		path = getPath(path);
		Zk zk = new Zk(cxnstr);
		zk.delete(path);
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr+"&path=" + StringUtils.substring(path, 0, StringUtils.lastIndexOf(path, "/"));
	}

	@RequestMapping("/rmrdel")
	public String rmrdel(Model model, String path, String data) {
		String cxnstr = getCxnstr();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		path = getPath(path);
		Zk zk = new Zk(cxnstr);
		zk.deleteRecursive(path);
		logger.info("deleteRecursive, cxnstr:{}, path:{}", cxnstr, path);
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr+"&path=" + StringUtils.substring(path, 0, StringUtils.lastIndexOf(path, "/"));
	}
	
	@RequestMapping("/deleteNode")
	public void deleteNode(HttpServletResponse response, String path) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		path = getPath(path);
		Zk zk = new Zk(cxnstr);
		zk.deleteRecursive(path);
		logger.info("deleteNode, cxnstr:{}, path:{}", cxnstr, path);
		writeResponse(response, res);
	}
	
	@RequestMapping("/renameNode")
	public void renameNode(HttpServletResponse response, String oldPath, String newPath) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		oldPath = getPath(oldPath);
		newPath = getPath(newPath);
		if("/".equals(oldPath) || "/".equals(newPath)) {
			res.setState(state);
			writeResponse(response, res);
		}
		Zk zk = new Zk(cxnstr);
		if(!ZkOperate.renameNode(zk.getClient().getZooKeeper(), oldPath, newPath)) {
			res.setState(state);
			res.setMsg("重命名失败。");
			writeResponse(response, res);
			return;
		}
		logger.info("renameNode, cxnstr:{}, oldPath:{}, newPath:{}", cxnstr, oldPath, newPath);
		writeResponse(response, res);
	}
	
	@RequestMapping("/copyPasteNode")
	public void copyPasteNode(HttpServletResponse response, String path, String targetPath) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		path = getPath(path);
		targetPath = getPath(targetPath);
		if("/".equals(path)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		Zk zk = new Zk(cxnstr);
		if(!ZkOperate.copyPasteNode(zk.getClient().getZooKeeper(), path, targetPath)) {
			res.setState(state);
			res.setMsg("复制失败，请确认是否已存在同名文件。");
			writeResponse(response, res);
			return;
		}
		logger.info("copyPasteNode, cxnstr:{}, path:{}, targetPath:{}", cxnstr, path, targetPath);
		writeResponse(response, res);
	}
	
	@RequestMapping("/cutPasteNode")
	public void cutPasteNode(HttpServletResponse response, String path, String targetPath) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		path = getPath(path);
		targetPath = getPath(targetPath);
		if("/".equals(path)) {
			res.setState(state);
			writeResponse(response, res);
			return;
		}
		Zk zk = new Zk(cxnstr);
		if(!ZkOperate.cutPasteNode(zk.getClient().getZooKeeper(), path, targetPath)) {
			res.setState(state);
			res.setMsg("移动或剪切粘贴失败，请确认是否已存在同名文件。");
			writeResponse(response, res);
			return;
		}
		logger.info("cutPasteNode, cxnstr:{}, path:{}, targetPath:{}", cxnstr, path, targetPath);
		writeResponse(response, res);
	}
	
	@RequestMapping("/backup")
	public String backup(HttpServletRequest request, Model model, String path) {
		String cxnstr = getCxnstr();
		HttpSession session = request.getSession();
		BaseMsg baseMsg = new BaseMsg();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		if (StringUtils.isBlank(path)) {
			baseMsg.addErrMsg("zookeeper备份路径不能为空！");
			session.setAttribute("baseMsg", baseMsg);
			return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr;
		}
		path = getPath(path);
		Zk zk = new Zk(cxnstr);
		if(!ZkOperate.backup(zk.getClient().getZooKeeper(), path, backupDirPath, cxnstr)) {
			baseMsg.addErrMsg("数据备份失败。");
		}
		session.setAttribute("baseMsg", baseMsg);
		logger.info("backup, cxnstr:{}, path:{}", cxnstr, path);
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr+"&path=" + path;
	}
	
	@RequestMapping("/openBackupFile")
	public void openBackupFile(HttpServletResponse response, String fileName) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			res.setMsg("取不到cxnstr！");
			writeResponse(response, res);
			return;
		}
		if (StringUtils.isBlank(fileName)) {
			res.setState(state);
			res.setMsg("取不到文件名！");
			writeResponse(response, res);
			return;
		}
		File fileDir = new File(backupDirPath, fileName);
		if (!fileDir.exists()) {
			res.setState(state);
			res.setMsg("备份文件目录不存在！path="+fileDir.getAbsolutePath());
			writeResponse(response, res);
			return;
		}
		File file = new File(fileDir, "0.properties");
		if (!file.exists()) {
			res.setState(state);
			res.setMsg("备份文件目录不存在！path="+file.getAbsolutePath());
			writeResponse(response, res);
			return;
		}
		String content = ComUtil.readFile(file);
		logger.info("openBackupFile, cxnstr:{}, fileName:{}", cxnstr, fileName);
		res.setData(content);
		writeResponse(response, res);
	}
	
	@RequestMapping("/recover")
	public String recover(HttpServletRequest request, Model model, String fileName) {
		String cxnstr = getCxnstr();
		BaseMsg baseMsg = new BaseMsg();
		HttpSession session = request.getSession();
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		if (StringUtils.isBlank(fileName)) {
			baseMsg.addErrMsg("备份文件不能为空！");
			session.setAttribute("baseMsg", baseMsg);
			return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr;
		}
		
		Zk zk = new Zk(cxnstr);
		File file = new File(backupDirPath, fileName);
		if (!ZkOperate.recover(zk.getClient().getZooKeeper(), file.getAbsolutePath())) {
			baseMsg.addErrMsg("数据还原失败。");
		}
		session.setAttribute("baseMsg", baseMsg);
		logger.info("backup, cxnstr:{}, fileName:{}", cxnstr, fileName);
		return "redirect:/read/addr?"+Constants.CX_STR+"="+cxnstr;
	}
	
	@RequestMapping("/deleteBackupFile")
	public void deleteBackupFile(HttpServletResponse response, String fileName) {
		String cxnstr = getCxnstr();
		Response res = new Response();
		int state = -1;
		if (StringUtils.isBlank(cxnstr)) {
			res.setState(state);
			res.setMsg("取不到cxnstr！");
			writeResponse(response, res);
			return;
		}
		if (StringUtils.isBlank(fileName)) {
			res.setState(state);
			res.setMsg("取不到文件名！");
			writeResponse(response, res);
			return;
		}
		File file = new File(backupDirPath, fileName);
		if (!file.exists()) {
			res.setState(state);
			res.setMsg("备份文件目录不存在！path="+file.getAbsolutePath());
			writeResponse(response, res);
			return;
		}
		if (ComUtil.deleteFolder(file)) {
			logger.info("deleteBackupFile, cxnstr:{}, fileName:{}", cxnstr, fileName);
			writeResponse(response, res);
		} else {
			res.setState(state);
			writeResponse(response, res);
		}
	}

	private String getCxnstr() {
		HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		return (String) req.getSession().getAttribute(Constants.CX_STR);
	}
	
	private void writeResponse(HttpServletResponse response, Response res) {
		response.setContentType("application/json;charset=UTF-8");
		try {
			response.getWriter().print(gson.toJson(res));
		} catch (IOException e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		}
	}
	
	private String getPath(String path){
		path = StringUtils.isBlank(path) ? SEPARATOR : StringUtils.trimToEmpty(path);
		path = StringUtils.endsWith(path, "/") && !"/".equals(path)? StringUtils.substring(path, 0, path.length()-1) : path;
		return path;
	}
}
